﻿//
// Copyright (c) 2024 BPer
//

#include <bperutil/sys/BPerThread.h>
#if !BPer_Enable_Phtread
#if BPer_OS_WIN
#include <process.h>


typedef struct{
    void* (*startfn)(void*);
    void* user;
}BPerThreadPara;



DWORD WINAPI bPer_thread_beginFn2( LPVOID lpParam ){
    BPerThreadPara* pThis = (BPerThreadPara*)lpParam;
    if(pThis){
        pThis->startfn(pThis->user);
    }
    bPer_free(pThis);
    return 0;
}

 int bPer_thread_create(bPer_thread_t* const thread, const void* attr,
                          void* (*startfn)(void*), void* arg) {
  (void)attr;
   BPerThreadPara* para=(BPerThreadPara*)bPer_calloc(sizeof (BPerThreadPara),1);
   para->user=arg;
   para->startfn=startfn;

   *thread = (bPer_thread_t)CreateThread(
               NULL,                   // default security attributes
               0,                      // use default stack size
               bPer_thread_beginFn2,       // thread function name
               para,          // argument to thread function
               0,                      // use default creation flags
               NULL);   // returns the thread identif
  if (*thread == NULL) return 1;
 // SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
  return 0;
}

 int bPer_thread_join(bPer_thread_t thread, void** value_ptr) {
  (void)value_ptr;
  return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 ||
          CloseHandle(thread) == 0);
}

// Mutex
 int bPer_thread_mutex_init(bPer_thread_mutex_t* const mutex, void* mutexattr) {
  (void)mutexattr;
  InitializeCriticalSection(mutex);
  return 0;
}

 int bPer_thread_mutex_lock(bPer_thread_mutex_t* const mutex) {
  EnterCriticalSection(mutex);
  return 0;
}

 int bPer_thread_mutex_unlock(bPer_thread_mutex_t* const mutex) {
  LeaveCriticalSection(mutex);
  return 0;
}

 int bPer_thread_mutex_destroy(bPer_thread_mutex_t* const mutex) {
  DeleteCriticalSection(mutex);
  return 0;
}

// Condition
 int bPer_thread_cond_destroy(bPer_thread_cond_t* const condition) {
  int err = 1;
  err &= (CloseHandle(condition->waiting_sem) != 0);
  err &= (CloseHandle(condition->received_sem) != 0);
  err &= (CloseHandle(condition->signal_event) != 0);
  return !err;
}

 int bPer_thread_cond_init(bPer_thread_cond_t* const condition, void* cond_attr) {
  (void)cond_attr;
  condition->waiting_sem = CreateSemaphore(NULL, 0, 1, NULL);
  condition->received_sem = CreateSemaphore(NULL, 0, 1, NULL);
  condition->signal_event = CreateEvent(NULL, FALSE, FALSE, NULL);
  if (condition->waiting_sem == NULL ||
      condition->received_sem == NULL ||
      condition->signal_event == NULL) {
    bPer_thread_cond_destroy(condition);
    return 1;
  }
  return 0;
}

 int bPer_thread_cond_signal(bPer_thread_cond_t* const condition) {
  int err = 1;
  if (WaitForSingleObject(condition->waiting_sem, 0) == WAIT_OBJECT_0) {
    // a thread is waiting in bPer_thread_cond_wait: allow it to be notified
    err = SetEvent(condition->signal_event);
    // wait until the event is consumed so the signaler cannot consume
    // the event via its own bPer_thread_cond_wait.
    err &= (WaitForSingleObject(condition->received_sem, INFINITE) !=
           WAIT_OBJECT_0);
  }
  return !err;
}

 int bPer_thread_cond_wait(bPer_thread_cond_t* const condition,
                             bPer_thread_mutex_t* const mutex) {
  int err=1;
            // note that there is a consumer available so the signal isn't dropped in
  // bPer_thread_cond_signal
  if (!ReleaseSemaphore(condition->waiting_sem, 1, NULL))
    return 1;
  // now unlock the mutex so bPer_thread_cond_signal may be issued
  bPer_thread_mutex_unlock(mutex);
  err = (WaitForSingleObject(condition->signal_event, INFINITE) ==
        WAIT_OBJECT_0);
  err &= ReleaseSemaphore(condition->received_sem, 1, NULL);
  bPer_thread_mutex_lock(mutex);
  return !err;
}
#endif
#endif


